// formats.cpp
// Customizer_Base
// Protea Customizer/Customizer Pro / Business Logic for managing formats (buffers)
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Please send correspondence to:
//
// theproteaproject@gmail.com
//

#include "base_setup.h"



//@ SEC 3

//@ CHA Format Descriptor Verify

//@ COD FormatDescVerify

//@ TAB FormatDescriptr Read

//@ GEN Use FieldDescVerify to verify a format record

void FormatDescVerify( XCBuffer* input, verify_type verify_mode, XCTransactionVars* vars, bool pro_mode, XCBuffer* orig ) {

	TRANS_INFUNC( FormatDescVerify );



	XCBuffer* Parent = NULL;

	XCDBStatement* stmt = NULL;



	XCSQLGen* query = vars->query;



	try {

		if (!orig)

			orig = input;



		//@ SUB ValidateName to check for a valid name
		//@ ERR C (INV_FIELD_NAME)

		ValidateName( FLD_FORMAT_NAME, input, ERR_FORMAT, vars );


		//@ If verifying an ADD, COPY or CHANGE transaction:

		if (verify_mode == VERIFY_ADD || verify_mode == VERIFY_COPY || verify_mode == VERIFY_CHANGE) {

			//@ GRS



			//@ Verify that the format type is valid

			if (!input->GetField( FLD_FORMAT_TYPE )->CheckInRange( 0, 12 ))

				vars->Errors->Add( ERR_INV_FORMAT_TYPE, SEV_CRITICAL, FLD_FORMAT_TYPE );

			//@ GRE

		};



		//@ If verifying an ADD or CHANGE transaction:

		if (verify_mode == VERIFY_ADD || verify_mode == VERIFY_CHANGE) {

			//@ GRS

			//@ If this is a table buffer, then verify that DATABASE_NAME is supplied

			XCField* temp = vars->buffer->GetField( FLD_DATABASE_NAME );

			bool is_table = IsDatabaseBuffer( input );

			if (is_table && (!temp || temp->IsBlank()))

				vars->Errors->Add( ERR_MUST_SUPPLY_DATABASE, SEV_CRITICAL );

			//@ GRE

		};



		//@ If verifying an ADD transaction,

		if (verify_mode == VERIFY_ADD || verify_mode == VERIFY_COPY) {

			//@ GRS



			//@ UTL LookupNumberFromName to convert format name into a format number

			//@ ERR C (ALREADY_EXISTS) Format already exists

			if ( LookupNumberFromName( vars, vars->buffer, input, FLD_FORMAT_NUMBER, FLD_FORMAT_NAME, FMT_FORMAT_DESCRIPTR ))

				vars->Errors->Add( ERR_ALREADY_EXISTS, SEV_CRITICAL, FLD_FORMAT_NAME, 1, ERR_FORMAT );



			//@ GRE

		} else if (verify_mode == VERIFY_CHANGE) {

			//@ If verifying a CHANGE transaction

			// We assume that the change transaction sent us a format number

			//@ GRS

			//@ SUB FormatDescRetrieve Verify the we do have a format with this name

			//@ ERR E (DOESNT_EXIST) Format doesn't exist

			if (!FormatDescRetrieve( orig, vars ))

				vars->Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_FORMAT_NAME, 1, ERR_FORMAT );

			//@ GRE

		} else {

			//@ ELSE

			//@ GRS

			

			//@ SUB FormatDescRetrieve Verify the we do have a format with this name

			//@ ERR E (DOESNT_EXIST) Format doesn't exist

			if ( ! LookupNumberFromName( vars, vars->buffer, orig, FLD_FORMAT_NUMBER, FLD_FORMAT_NAME, FMT_FORMAT_DESCRIPTR ) || 

				!FormatDescRetrieve( orig, vars ))

				vars->Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_FORMAT_NAME, 1, ERR_FORMAT );

			//@ GRE

		};



		//@ If verifying a DELETE transaction:

		if (verify_mode == VERIFY_DELETE) {

			//@ GRS

			//@ Check to see if the format is a child of any other formats

			Parent = input->Copy();

			Parent->MoveUnlikeField( FLD_CHILD_FORMAT, Parent, FLD_FORMAT_NUMBER );



			query->MakeSELECT( Parent );

			query->AddWHERE( 2, Parent->GetField( FLD_APPL_NBR ), Parent->GetField( FLD_CHILD_FORMAT ) );

			stmt = vars->dbtxn->ExecuteSQL( query );

			if (!stmt->Eof())

				vars->Errors->Add( ERR_FORMAT_IS_CHILD_CANT_DELETE, SEV_CRITICAL, FLD_FORMAT_NAME, 1, Parent->GetField( FLD_FORMAT_NAME ) );



			//@ Do not allow deletions of critical formats in pro version

			if (!pro_mode) {

				if (input->GetField( FLD_CRITICAL_FORMAT )->GetLong(true))

					vars->Errors->Add( ERR_CRITICAL_BUFFER, SEV_CRITICAL );

			};



			//@ GRE

		};



		//@ If verifying an ADD or CHANGE transaction:

		if (verify_mode == VERIFY_ADD || verify_mode == VERIFY_COPY || verify_mode == VERIFY_CHANGE) {

			//@ GRS

			//@ If the CHILD_NAME field exists, and has a value:

			XCField* temp = vars->buffer->GetField( FLD_CHILD_NAME );

			if (temp && !temp->IsBlank()) {

				//@ GRS

				//@ SUB LookupNumberFromName Change CHILD_NAME into CHILD_FORMAT

				//@ ERR ERR_ALREADY_EXISTS

				if ( !LookupNumberFromName( vars, vars->buffer, input, FLD_CHILD_FORMAT, FLD_CHILD_NAME, FMT_FORMAT_DESCRIPTR, FLD_FORMAT_NUMBER, FLD_FORMAT_NAME ))

					vars->Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_CHILD_NAME, 1, ERR_CHILD );

				//@ GRE

			} else

				input->GetField( FLD_CHILD_FORMAT )->Clear();

			//@ GRE

		};

	} catch( ... ) {

		vars->myapp->CleanupObjects( 2, &Parent, &stmt );

		throw;

	};

	vars->myapp->CleanupObjects( 2, &Parent, &stmt );



	TRANS_OUTFUNC();

};









//@ SEC 3

//@ CHA Format Descriptor Retrieve

//@ COD FormatDescRetrieve

//@ TAB FormatDescriptr Read

//@ GEN Use FieldDescRetrieve to retrieve a format record



bool FormatDescRetrieve( XCBuffer* formatdesc, XCTransactionVars* vars ) {

	TRANS_INFUNC( FormatDescRetrieve );



	XCDBStatement* stmt;

	XCSQLGen* query = vars->query;

	bool result = true;



	//@ Attempt to read FORMAT_STRUCTURE record, if doesn't exist, show error

	//@ ERR C (INV_FORMAT_NBR) Invalid format number

	query->MakeFull( SQL_STMT_SELECT, formatdesc );

	try {

		stmt = vars->dbtxn->ExecuteSQL( query );

		if (stmt) {

			if (stmt->Eof())

				result = false;

		} else

			result = false;

	} catch( ... ) {

		App->CleanupObjects( 1, &stmt );

		throw;

	};

	App->CleanupObjects( 1, &stmt );



	TRANS_OUTFUNCRET( result );

};











//@ SEC 3

//@ CHA Format Descriptor Add

//@ COD FormatDescAdd

//@ TAB FormatDescriptr Write

//@ GEN Use FieldDescRetrieve to add a format record



void FormatDescAdd( XCBuffer* input, XCTransactionVars* vars, bool pro_mode ) {

	XCBuffer* format_pool = NULL;

	XCBuffer* format_desc = NULL;

	XCDBStatement* stmt = NULL;



	XCSQLGen* query = vars->query;

	XCField* fields[3];
	XCCompare comptemp[2];
	bool UsePool = false;

	bool AlreadySupplied = false;



	TRANS_INFUNC( FormatDescAdd );



	try {

		if (input->GetField( FLD_FORMAT_NUMBER )->Compare(0) == 0) {

			//@ Determine the next available format number

			//@ GRS

			//@ Attempt to read records from FORMAT_NBR_POOL

			format_pool = App->CreateBuffer( FMT_FORMAT_NBR_POOL, false );

			format_pool->MoveField( input, FLD_APPL_NBR );
			fields[0] = format_pool->GetField( FLD_APPL_NBR );
			fields[1] = format_pool->GetField( FLD_FORMAT_NUMBER );
			fields[1]->Clear();
			fields[2] = NULL;
			comptemp[1].comparison = pro_mode ? cmp_greaterthan : cmp_lessthan;


			query->MakeSELECT( format_pool );

			query->AddWHERE( fields, comptemp );
			stmt = vars->dbtxn->ExecuteSQL( query );

			UsePool = (!stmt->Eof());

			App->CleanupObjects( 1, &stmt );



			if (UsePool)

				input->MoveField( format_pool, FLD_FORMAT_NUMBER );

			else {

				//@ Grab the next available format number
				format_desc = App->CreateBuffer( FMT_FORMAT_DESCRIPTR, false );
				format_desc->MoveCorresponding( input, vars->Errors );

				XCField* list[3];
				XCCompare comp[2];
				list[0] = format_desc->GetField( FLD_APPL_NBR );
				list[1] = format_desc->GetField( FLD_FORMAT_NUMBER );
				list[1]->Clear();
				list[2] = NULL;

				XCOrder order;
				order.field = list[1];
				if (pro_mode) {
					order.direction = order_desc;
					comp[1].comparison = cmp_greaterthan;
				} else {
					order.direction = order_asc;
					comp[1].comparison = cmp_lessthan;
				};

				query->MakeSELECT( format_desc );
				query->AddWHERE( list, comp ); 
				query->AddORDERBY( &order );
				vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

				//@ Set next field number (either plus or minus)
				if (pro_mode)
					format_desc->AddConst( FLD_FORMAT_NUMBER, 1 );
				else
					format_desc->SubConst( FLD_FORMAT_NUMBER, 1 );

				//@ Move the field number from the APPL_DEFN record to the input buffer
				input->MoveField( format_desc, FLD_FORMAT_NUMBER );
			};

		//@ GRE

		} else

			AlreadySupplied = true;



		//@ Insert the FORMAT_DESCRIPTOR record

		query->MakeFull( SQL_STMT_INSERT, input );

		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );



		//@ If we used a pool record, then remove it

		if (UsePool) {

			query->MakeFull( SQL_STMT_DELETE, format_pool );

			vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

		};

	} catch( ... ) {

		App->CleanupObjects( 3, &format_pool, &format_desc, &stmt );

		throw;

	};

	App->CleanupObjects( 3, &format_pool, &format_desc, &stmt );



	TRANS_OUTFUNC();

};













//@ SEC 3

//@ CHA Format Descriptor Change

//@ COD FormatDescChange

//@ TAB FormatDescriptor Write

//@ GEN Use FormatDescChange to update a format record



void FormatDescChange( XCBuffer* input, XCBuffer* orig, XCTransactionVars* vars ) {

	XCSQLGen* query = vars->query;



	TRANS_INFUNC( FormatdDescChange );



	XCDBStatement* stmt = NULL;

	XCBuffer* dd = NULL;

	XCBuffer* ds = NULL;
	XCBuffer* fd = NULL;


	try {

		input->DebugDump();

		orig->DebugDump();



		//@ Issue update statement

		query->MakeFull( SQL_STMT_UPDATE, input, orig );

		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );



		//@ If the FORMAT_TYPE has changed, verify Data_structure records

		if (input->GetField( FLD_FORMAT_TYPE )->IsChanged()) {

			//@ GRS

			ds = vars->myapp->CreateBuffer( FMT_DATA_STRUCTURES );
			fd = vars->myapp->CreateBuffer( FMT_FIELD_DESCRIPTOR );

			ds->MoveCorresponding( input, vars->Errors );
			stmt = DataStructureReviewFormat( ds, vars );
			while (!stmt->Eof()) {

				fd->MoveCorresponding( ds, vars->Errors );

				if (FieldDescRetrieve( fd, vars ))

					FixFieldType( input, fd, ds, vars );
				stmt->MoveNext();

			}; // while stmt



			//@ Check to see if we are no longer a database type, if so, delete DATASET_DESCR record

			if (IsDatabaseBuffer( orig ) && !IsDatabaseBuffer( input )) {

				//@ GRS

				dd = vars->myapp->CreateBuffer( FMT_DATASET_DESCR );

				dd->MoveCorresponding( input, vars->Errors );



				//@ SUB DatasetDescrDelete to delete the DATASET_DESCR record

				DatasetDescrDelete( dd, vars );



				//@ GRE

			};



			//@ GRE

		};

	} catch( ... ) {

		vars->myapp->CleanupObjects( 4, &stmt, &dd, &ds, &fd );

		throw;

	};

	vars->myapp->CleanupObjects( 4, &stmt, &dd, &ds, &fd );



	TRANS_OUTFUNC();

};













//@ SEC 3

//@ CHA Format Descriptor Delete

//@ COD FormatDescDelete

//@ TAB FormatDescriptr Write

//@ GEN Use FieldDescDelete to delete a format record



void FormatDescDelete( XCBuffer* input, XCTransactionVars* vars ) {

	XCSQLGen* query = vars->query;

	XCBuffer* dd = NULL;

	XCBuffer* db = NULL;

	XCBuffer* ds = NULL;

	XCBuffer* pool = NULL;



	TRANS_INFUNC( FormatDescDelete );



	try {

		//@ Check if format defined in DATASET_DESCR

		dd = App->CreateBuffer( FMT_DATASET_DESCR, false );

		dd->MoveField( input, FLD_APPL_NBR );

		dd->MoveField( input, FLD_FORMAT_NUMBER );

		query->MakeDELETE( dd );

		query->AddWHERE( 2,

			dd->GetField( FLD_FORMAT_NUMBER ),

			dd->GetField( FLD_APPL_NBR ) );

		try {

			vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

		} catch( ... ) {};



		//@ Delete any DB_RELATE records for this FORMAT_NUMBER

		XCBuffer* db = App->CreateBuffer( FMT_DB_RELATE, false );

		db->MoveField( input, FLD_FORMAT_NUMBER );

		db->MoveField( input, FLD_APPL_NBR );

		query->MakeDELETE( db );

		query->AddWHERE( 2, 

			db->GetField( FLD_FORMAT_NUMBER ),

            db->GetField( FLD_APPL_NBR ) );

		try { 

			vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

		} catch( ... ) {};



		//@ Delete DATA_STRUCTURES records for this FORMAT_NUMBER

		XCBuffer* ds = App->CreateBuffer( FMT_DATA_STRUCTURES, false );

		ds->MoveField( input, FLD_FORMAT_NUMBER );

		ds->MoveField( input, FLD_APPL_NBR );

		query->MakeDELETE( ds );

		query->AddWHERE( 2,

			ds->GetField( FLD_FORMAT_NUMBER ),

			ds->GetField( FLD_APPL_NBR ) );

		try {

			vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

		} catch( ... ) {};



		//@ Delete FORMAT_DESCRIPTR record

		query->MakeFull( SQL_STMT_DELETE, input );

		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );



		//@ Insert record into FORMAT_NBR_POOL

		pool = App->CreateBuffer( FMT_FORMAT_NBR_POOL, false );

		pool->MoveCorresponding( input, vars->Errors );

		query->MakeFull( SQL_STMT_INSERT, pool );

		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

		App->CleanupObjects( 4, &dd, &ds, &db, &pool );

	} catch( ... ) {

		App->CleanupObjects( 4, &dd, &ds, &db, &pool );

		throw;

	};

	TRANS_OUTFUNC();

};











//@ SEC 3

//@ CHA Format Descriptor Delete All

//@ COD FormatDescDeleteAll

//@ TAB FormatDescriptr Write

//@ GEN Use FieldDescDeleteAll to delete all format records



void FormatDescDeleteAll( XCBuffer* input, XCTransactionVars* vars ) {

	XCCompare comp[2];

	XCField* fields[3];

	XCSQLGen* query = vars->query;



	XCBuffer* dd = NULL;

	XCBuffer* db = NULL;

	XCBuffer* ds = NULL;

	XCBuffer* format = NULL;

	XCBuffer* pool = NULL;



	TRANS_INFUNC( FormatDescDeleteAll );



	try {

		//@ Check if format defined in DATASET_DESCR

		dd = App->CreateBuffer( FMT_DATASET_DESCR, false );

		dd->MoveField( input, FLD_APPL_NBR );

		query->MakeDELETE( dd );



		fields[0] = dd->GetField( FLD_APPL_NBR );

		fields[1] = NULL;

		query->AddWHERE( fields, comp );

		try {

			vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

		} catch( ... ) {};



		//@ Delete any DB_RELATE records for this FORMAT_NUMBER

		db = App->CreateBuffer( FMT_DB_RELATE, false );

		db->MoveField( input, FLD_APPL_NBR );

		query->MakeDELETE( db );



		fields[0] = db->GetField( FLD_APPL_NBR );

		query->AddWHERE( fields, comp );

		try {

			vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

		} catch( ... ) {};



		//@ Delete DATA_STRUCTURES records for this FORMAT_NUMBER

		ds = App->CreateBuffer( FMT_DATA_STRUCTURES, false );



		ds->MoveField( input, FLD_APPL_NBR );

		query->MakeDELETE( ds );



		fields[0] = ds->GetField( FLD_APPL_NBR );

		query->AddWHERE( fields, comp );

		try {

			vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

		} catch( ... ) {};



		//@ Delete FORMAT_DESCRIPTR records

		format = App->CreateBuffer( FMT_FORMAT_DESCRIPTR, false );

		format->MoveField( input, FLD_APPL_NBR );

		query->MakeDELETE( format );

		fields[0] = format->GetField( FLD_APPL_NBR );

		query->AddWHERE( fields, comp );

		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );



		//@ Create a FORMAT_NBR_POOL buffer, move in APPL_NBR

		pool = App->CreateBuffer( FMT_FORMAT_NBR_POOL, false );

		pool->MoveField( input, FLD_APPL_NBR );



		//@ Delete FIELD_NBR_POOL records

		query->MakeDELETE( pool );

		query->AddWHERE( 1, pool->GetField( FLD_APPL_NBR ) );

		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

	} catch( ... ) {

		App->CleanupObjects( 5, &dd, &ds, &db, &format, &pool );

	};

	App->CleanupObjects( 5, &dd, &ds, &db, &format, &pool );



	TRANS_OUTFUNC();

};







//////////////////////////////////////////////////////////
//
// Internal functions
//
//////////////////////////////////////////////////////////






//@ SEC 2
//@ CHA AddFormatInternal
//@ COD AddFormatInternal
void AddFormatInternal( XCTransactionVars* vars, bool pro_mode ) {
	XCBuffer* TransBuf = NULL;

	XCBuffer* dd = NULL;


	try {
		//@ Create format descriptor buffer

		TransBuf = vars->myapp->CreateBuffer( FMT_FORMAT_DESCRIPTR, false );



		//@ Move screen info to transaction buffer

		TransBuf->MoveCorresponding( vars->buffer, vars->Errors );



		TransBuf->DebugDump();



		// If the supplied buffer is anything other than FORMAT_DESCRIPTR then don't allow setting of FORMAT_NUMBER

		if (vars->buffer->GetFormatNumber() != FMT_FORMAT_DESCRIPTR)

			TransBuf->GetField( FLD_FORMAT_NUMBER )->Clear();



		//@ SUB FormatDescVerify to verify new format desc. record

		FormatDescVerify( TransBuf, VERIFY_ADD, vars, pro_mode );

		vars->Errors->Check();



		//@ SUB FormatDescAdd to add the new record

		FormatDescAdd( TransBuf, vars, pro_mode );



		//@ Do we need to add a new DATASET_DESCR record?

		if (IsDatabaseBuffer( TransBuf )) {

			//@ GRS

			//@ Create a DATASET_DESCR buffer

			dd = vars->myapp->CreateBuffer( FMT_DATASET_DESCR, false );

			dd->MoveCorresponding( TransBuf, vars->Errors );



			//@ Convert DATABASE_NAME to DATABASE_NBR

			if (!LookupNumberFromName( vars, vars->buffer, dd, FLD_DATABASE_NBR, FLD_DATABASE_NAME, FMT_DATABASE_DEFN ))

				vars->Errors->Add( ERR_MUST_SUPPLY_DATABASE, SEV_CRITICAL );



			//@ SUB DatasetDescrAdd to add the new record

			DatasetDescrAdd( dd, vars );

			//@ GRE

		};



		vars->buffer->MoveCorresponding( TransBuf, vars->Errors );

	} catch( ... ) {
		vars->myapp->CleanupObjects( 2, &TransBuf, &dd );

		throw;
	};
	vars->myapp->CleanupObjects( 2, &TransBuf, &dd );

};






//@ SEC 2
//@ CHA DelFormatInternal
//@ COD DelFormatInternal
void DelFormatInternal( XCTransactionVars* vars, bool pro_mode ) {
	XCBuffer* TransBuf = NULL;


	try {
		//@ Create format descriptor buffer

		TransBuf = vars->myapp->CreateBuffer( FMT_FORMAT_DESCRIPTR, false );	



		//@ Move supplied buffer information into transaction buffer

		TransBuf->MoveCorresponding( vars->buffer, vars->Errors );



		//@ UTL LookupNumberFromName to convert format name into a format number

		LookupNumberFromName( vars, vars->buffer, TransBuf, FLD_FORMAT_NUMBER, FLD_FORMAT_NAME, FMT_FORMAT_DESCRIPTR );

		vars->Errors->Check();



		//@ SUB FormatDescVerify to verify a format descriptor record

		FormatDescVerify( TransBuf, VERIFY_DELETE, vars, pro_mode );

		vars->Errors->Check();



		//@ SUB FormatDescDelete to delete the format descriptor record

		FormatDescDelete( TransBuf, vars );

	} catch( ... ) {
		vars->myapp->CleanupObjects( 1, &TransBuf );

		throw;
	};
	vars->myapp->CleanupObjects( 1, &TransBuf );

};







//@ SEC 2
//@ CHA ChgFormatInternal
//@ COD ChgFormatInternal
void ChgFormatInternal( XCTransactionVars* vars, bool pro_mode ) {
	XCBuffer* TransBuf = NULL;

	XCBuffer* OrigBuf = NULL;

	XCBuffer* dd = NULL;



	XCField* temp;



	try {

		//@ Create a FORMAT_DESCRIPTR buffer

		TransBuf = vars->myapp->CreateBuffer( FMT_FORMAT_DESCRIPTR, true );



		//@ Move screen data into copy buffer

		TransBuf->MoveCorresponding( vars->buffer, vars->Errors, true );



		//@ Create a copy of the transaction buffer

		OrigBuf = TransBuf->Copy();



		//@ Check for errors.

		vars->Errors->Check();



		//@ SUB FieldDescValidate to validate input data

		FormatDescVerify( TransBuf, VERIFY_CHANGE, vars, pro_mode, OrigBuf );



		//@ Check for validation errors

		vars->Errors->Check();



		//@ SUB FormatDescChange change field record

		FormatDescChange( TransBuf, OrigBuf, vars );



		//@ Now create a DATASET_DESCR record if necessary
		if (IsDatabaseBuffer( TransBuf )) {
			//@ GRS

			//@ Create a DATASET_DESCR record
			dd = vars->myapp->CreateBuffer( FMT_DATASET_DESCR );

			//@ Move values from the SOURCE into the DATASET_DESCR record
			dd->MoveCorresponding( TransBuf, vars->Errors );

			//@ SUB DatasetDescrRetrieve Retrieve the DATASET_DESCR value from database, if it exists
			bool has_record = DatasetDescrRetrieve( dd, vars );

			//@ Lookup new DATABASE_NAME record
			if (!LookupNumberFromName( vars, vars->buffer, dd, FLD_DATABASE_NBR, FLD_DATABASE_NAME, FMT_DATABASE_DEFN ))

				vars->Errors->Add( ERR_MUST_SUPPLY_DATABASE, SEV_CRITICAL );


			//@ If we were able to read a record,
			if (has_record) {
				//@ GRS
				//@ SUB DatasetDescrChange To change the existing record
				DatasetDescrChange( dd, vars );
				//@ GRE
			} else { //@ ELSE
				//@ GRS
				//@ SUB DatasetDescrAdd Add the new DATASET_DESCR record
				DatasetDescrAdd( dd, vars );
				//@ GRE
			};

			//@ GRE
		} else if (IsDatabaseBuffer( OrigBuf )) {
			//@ Remove the DATASET_DESCR record if necessary
			//@ GRS

			//@ Create a DATASET_DESCR record
			dd = vars->myapp->CreateBuffer( FMT_DATASET_DESCR );

			//@ Move values from the SOURCE into the DATASET_DESCR record
			dd->MoveCorresponding( TransBuf, vars->Errors );

			//@ SUB DatasetDescrDelete Delete the DATASET_DESCR record
			DatasetDescrDelete( dd, vars );

			//@ GRE
		};

		//@ Return child format name

		temp = vars->buffer->GetField( FLD_CHILD_NAME );

		if (temp && TransBuf->GetField( FLD_CHILD_FORMAT )->GetLong( true ) > 0) {

			//@ GRS

			//@ SUB LookupNumberFromName Change CHILD_FORMAT into CHILD_NAME

			LookupNameFromNumber( vars, TransBuf, vars->buffer, FLD_CHILD_FORMAT, FLD_CHILD_NAME, FMT_FORMAT_DESCRIPTR, FLD_FORMAT_NUMBER, FLD_FORMAT_NAME );

			//@ GRE

		};

		vars->buffer->MoveCorresponding( TransBuf, vars->Errors );

	} catch( ... ) {

		vars->myapp->CleanupObjects( 3, &TransBuf, &OrigBuf, &dd );

		throw;

	};

	vars->myapp->CleanupObjects( 3, &TransBuf, &OrigBuf, &dd );

};









//@ SEC 2
//@ CHA CopyFormatInternal
//@ COD CopyFormatInternal
void CopyFormatInternal( XCTransactionVars* vars, bool pro_mode ) {
	XCBuffer* SourceBuf = NULL;

	XCBuffer* DestBuf = NULL;

	XCBuffer* DSBuf = NULL;

	XCBuffer* dd = NULL;

	XCBuffer* DBRelate = NULL;

	XCDBStatement* stmt = NULL;


	try {
		//@ Create format descriptor buffer

		SourceBuf = vars->myapp->CreateBuffer( FMT_FORMAT_DESCRIPTR, false );

		DestBuf = vars->myapp->CreateBuffer( FMT_FORMAT_DESCRIPTR, false );

		DSBuf = vars->myapp->CreateBuffer( FMT_DATA_STRUCTURES, false );



		//@ Move screen info to transaction buffer

		SourceBuf->MoveCorresponding( vars->buffer, vars->Errors );



		//@ SUB FormatDescVerify to verify source format record

		FormatDescVerify( SourceBuf, VERIFY_REVIEW, vars, pro_mode );

		vars->Errors->Check();



		//@ SUB FormatDescVerify to verify new format record

		vars->buffer->MoveUnlikeField( FLD_FORMAT_NAME, vars->buffer, FLD_TGT_FORMAT_NAME );

		DestBuf->MoveCorresponding( SourceBuf, vars->Errors );

		DestBuf->MoveCorresponding( vars->buffer, vars->Errors );

		DestBuf->DebugDump();

		FormatDescVerify( DestBuf, VERIFY_COPY, vars, pro_mode );

		vars->Errors->Check();



		//@ SUB FormatDescAdd to add the new record

		FormatDescAdd( DestBuf, vars, pro_mode );



		//@ Now copy all the data structure records

		DSBuf->MoveCorresponding( SourceBuf, vars->Errors );

		stmt = DataStructureReviewFormat( DSBuf, vars );
		while (!stmt->Eof()) {
			//@ GRS
			DSBuf->MoveField( DestBuf, FLD_FORMAT_NUMBER );

			// Reset the critical fields
			DSBuf->GetField( FLD_CRITICAL_FIELD )->Clear();

			//@ SUB DataStructureAdd to add the new record
			DataStructureAdd( DSBuf, NULL, NULL, vars );

			//@ Move to next record
			stmt->MoveNext();
			//@ GRE
		};

		//@ Now create a DATASET_DESCR record if necessary
		if (IsDatabaseBuffer( DestBuf )) {
			//@ GRS

			//@ Create a DATASET_DESCR record
			dd = vars->myapp->CreateBuffer( FMT_DATASET_DESCR );

			//@ Move values from the SOURCE into the DATASET_DESCR record
			dd->MoveCorresponding( SourceBuf, vars->Errors );

			//@ SUB DatasetDescrRetrieve Retrieve the DATASET_DESCR value from database
			if (!DatasetDescrRetrieve( dd, vars ))
				vars->Errors->Add( 1 );

			//@ Overlay DEST data into DATASET_DESCR record
			dd->MoveCorresponding( DestBuf, vars->Errors );

			//@ SUB DatasetDescrAdd Add the new DATASET_DESCR record
			DatasetDescrAdd( dd, vars );

			//@ Copy all the database relation records now
			DBRelate = vars->myapp->CreateBuffer( FMT_DB_RELATE, false );

			DBRelate->MoveCorresponding( SourceBuf, vars->Errors );

			stmt = DBRelateReviewFormat( DBRelate, vars );
			while (!stmt->Eof()) {
				DBRelate->MoveField( DestBuf, FLD_FORMAT_NUMBER );
				DBRelateAdd( DBRelate, vars );
				stmt->MoveNext();
			};

			//@ GRE
		};
	} catch( ... ) {

		vars->myapp->CleanupObjects( 6, &SourceBuf, &DestBuf, &DSBuf, &stmt, &dd, &DBRelate );

		throw;

	};

	vars->myapp->CleanupObjects( 6, &SourceBuf, &DestBuf, &DSBuf, &stmt, &dd, &DBRelate );

};
